package org.noip.amdg;

import java.awt.Cursor;
import java.awt.Font;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.MemoryImageSource;
import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.plaf.FontUIResource;

public class Game {

	/**
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) {
		setUIFont(new FontUIResource(null, Font.PLAIN, 18));
		new Game().start();
	}

	public static void setUIFont(javax.swing.plaf.FontUIResource f) {

		java.util.Enumeration<Object> keys = UIManager.getDefaults().keys();
		while (keys.hasMoreElements()) {
			Object key = keys.nextElement();
			Object value = UIManager.get(key);
			if (value instanceof javax.swing.plaf.FontUIResource)
				UIManager.put(key, f);
		}
	}

	final private GameModel model;
	final private GamePane pane;
	final private SoundPlayer soundPlayer;
	final private JFrame frame;
	final private LinkedBlockingQueue<GameEvent> events = new LinkedBlockingQueue<GameEvent>();
	final private Egg egg = new Egg();

	public Game() {
		model = new GameModel();
		frame = new JFrame();

		Image image = Toolkit.getDefaultToolkit().createImage(
				new MemoryImageSource(16, 16, new int[16 * 16], 0, 16));
		Cursor clearCursor = Toolkit.getDefaultToolkit().createCustomCursor(
				image, new Point(0, 0), "clearCursor");

		pane = new GamePane(model);
		pane.setCursor(clearCursor);
		frame.setContentPane(pane);

		frame.setSize(920, 600);
		frame.setTitle("Funnels & Buckets");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);

		model.addGameEventListener(new GameEventListener() {

			public void addEvent(GameEvent event) {
				events.add(event);
			}
		});

		SoundPlayer soundPlayer = null;
		try {
			soundPlayer = new SoundPlayer();
			model.addGameEventListener(soundPlayer);
		} catch (UnsupportedAudioFileException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (LineUnavailableException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidMidiDataException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MidiUnavailableException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.soundPlayer = soundPlayer;

	}

	public void start() {
		model.startGame();

		frame.addKeyListener(new KeyListener() {

			public void keyTyped(KeyEvent e) {
				// TODO Auto-generated method stub

			}

			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub

			}

			public void keyPressed(KeyEvent e) {
				if (egg.step(e)) {
					(new Thread() {
						public void run() {
							runAnimation(new WinAnimation());
						}
					}).start();
				}
				switch (e.getKeyChar()) {
				case 'm':
				case 'M':
					if (soundPlayer != null)
						soundPlayer.toggleMusic();
					break;
				case KeyEvent.VK_ESCAPE:
					if (soundPlayer != null)
						soundPlayer.stopMusic();
					frame.dispose();
					try {
						Thread.sleep(500);
					} catch (InterruptedException e1) {

					}
					System.exit(0);
				default:
					model.registerKey(e.getKeyChar());
				}

			}
		});
		
		if (soundPlayer != null) {
			soundPlayer.startThread();
		}
		
		while (true) {
			GameEvent event = null;
			try {
				event = events.take();
			} catch (InterruptedException e) {
			}

			if (event != null) {
				switch (event.type) {
				case LEVEL_UP:
					runAnimation(new LevelAnimation(model.getLevel()));
				default:
					pane.repaint();

				}
			}
		}

	}

	private void runAnimation(Animation animation) {
		pane.setCurrentAnimation(animation);
		while (!animation.isDone()) {
			pane.repaint();
			try {
				Thread.sleep(animation.getStepTime());
			} catch (InterruptedException e) {
			}
		}
	}

}
